package org.spring.util;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;


public class BeanFactory {

    private ConcurrentHashMap<String,Object> map = new ConcurrentHashMap();

    public BeanFactory() {
        parseXml();
    }

    private void parseXml() {
        File file = new File(this.getClass().getResource("/").getPath()+"/spring.xml");
        SAXReader saxReader = new SAXReader();
        try {
            Document doc = saxReader.read(file);
            Element rootElement = doc.getRootElement();
            //定义自动注入
            Attribute defaultAutowiredAttribute = rootElement.attribute("default-autowired");
            boolean flag = false;
            if (defaultAutowiredAttribute != null) {
                flag = true;
            }
            int count = 0;
            for(Iterator<Element> it = rootElement.elementIterator();it.hasNext();){
                //TODO 1.构造实例对象
                Element firstChild = it.next();
                Attribute idAttribute = firstChild.attribute("id");
                String beanName = idAttribute.getValue();
                Attribute classAttribute = firstChild.attribute("class");
                String clazzName = classAttribute.getValue();
                Class<?> clazz = Class.forName(clazzName);

                //TODO 2.维护依赖关系,判断是否有property,或者判断类是否有属性,有则注入,通过解析xml的形式进行注入,上面的是自动注入
                Object object = null;
                for(Iterator<Element> secondIt = firstChild.elementIterator();secondIt.hasNext();){
                    Element secondChildElement = secondIt.next();
                    if (secondChildElement.getName().equals("property")) {
                        //使用setter,没有特殊的构造函数
                        object = clazz.newInstance();
                        String refValue = secondChildElement.attribute("ref").getValue();
                        Object injectObj = map.get(refValue);

                        //获取对应的name
                        String nameValue = secondChildElement.attribute("name").getValue();
                        Field field = clazz.getDeclaredField(nameValue);
                        field.setAccessible(true);
                        //设置field
                        field.set(object,injectObj);
                    }else{
                        //存在特殊构造器
                        String refValue = secondChildElement.attribute("ref").getValue();
                        Object injectObj = map.get(refValue);
                        Class<?> injectObjClass = injectObj.getClass();
                        Constructor<?> constructor = clazz.getConstructor(injectObjClass.getInterfaces()[0]);
                        object = constructor.newInstance(injectObj);
                    }

                }

                if (flag) {
                    if (defaultAutowiredAttribute.getValue().equals("byType")) {
                        //判断是否存在依赖
                        for (Field field : clazz.getDeclaredFields()) {
                            Class<?> fieldType = field.getType();

                            Object injectObj = null;
                            for (String key:map.keySet()) {
                                Class<?> innnerCdlass = map.get(key).getClass().getInterfaces()[0];
                                if (innnerCdlass.getName().equals(fieldType.getName())) {
                                    injectObj = map.get(key);
                                    count++;
                                }
                            }
                            if (count>1) {
                                throw new SpringException("需要一个对象，但找到两个对象");
                            }else{
                                object = clazz.newInstance();
                                field.setAccessible(true);
                                field.set(object,injectObj);
                            }
                        }
                    }
                }

                //没有子标签
                if (object == null) {
                     object = clazz.newInstance();
                }

                map.put(beanName,object);
                System.out.println(map);
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (Exception e){
            e.printStackTrace();
        }
    }


    public Object getBean(String beanName) {
        return map.get(beanName);
    }
}
